package main

import (
	"fmt"
	"sync"
	"time"
)

func worker(ch chan int) {
	for {
		//fmt.Println("x")
		//time.Sleep(2000 * time.Millisecond)
		fmt.Printf("%d ", <-ch) //通道中没有值会阻塞，通道关闭则非阻塞，读取0值

		//fmt.Println("y")
	}
}

func chDemo1() {
	ch := make(chan int)
	go worker(ch)
	for i := 0; i < 2; i++ {
		ch <- i //阻塞
	}
	//time.Sleep(time.Millisecond)
}

var result []int

func createWorker(i int) chan int {
	ch := make(chan int)
	go func(i int) {
		for {
			//每个gorountine都会按顺序接收channel中的数据，但打印的数据无法保证
			fmt.Printf("channel:%d - %c\n", i, <-ch)
			//result = append(result, <-ch)
		}
	}(i)

	return ch
}

const th = 10

func chDemo2() {
	var chs [th]chan int
	for i := 0; i < th; i++ {
		chs[i] = createWorker(i)
	}

	for i := 0; i < th; i++ {
		chs[i] <- 'a' + i
	}
	for i := 0; i < th; i++ {
		chs[i] <- 'A' + i
	}
	time.Sleep(time.Millisecond)
	for _, v := range result {
		fmt.Printf("%c ", v)
	}
}

func createWorker3(i int) chan<- int { //限制返回的channel只能是只进不出的
	ch := make(chan int)
	go func(i int) {
		for {
			//每个gorountine都会按顺序接收channel中的数据，但打印的数据无法保证
			fmt.Printf("channel:%d - %c\n", i, <-ch)
			//result = append(result, <-ch)
		}
	}(i)

	return ch
}

func chDemo3() {
	var chs [th]chan<- int
	for i := 0; i < th; i++ {
		chs[i] = createWorker3(i)
	}

	for i := 0; i < th; i++ {
		chs[i] <- 'a' + i
		//n := <-chs[i]
	}
	for i := 0; i < th; i++ {
		chs[i] <- 'A' + i
	}
	time.Sleep(time.Millisecond)
	for _, v := range result {
		fmt.Printf("%c ", v)
	}
}

func worker4(ch chan int) {

	for {
		//n ,ok := <-ch
		fmt.Printf("channel:%d ", <-ch)
		time.Sleep(1000 * time.Millisecond)
	}

	//for n := range ch { //用for range循环通道，如果通道未关闭，会阻塞。
	//	//fmt.Println(111)
	//	fmt.Printf("channel range:%d ", n)
	//	//fmt.Println(222)
	//}
	////fmt.Println(333)
}
func chDemo4() {
	ch := make(chan int, 3)
	go worker4(ch)
	ch <- 1
	ch <- 2
	ch <- 3
	ch <- 4
	close(ch) //通道关闭后，ch仍然可以被取出0值 ； 发送方关闭通道
	time.Sleep(20000 * time.Millisecond)
}

func chDemo6() {
	timeout := time.After(5 * time.Second)

	fff()

	select {
	case <-timeout:
		fmt.Println(111)
		return
	default:
		fmt.Println(222)
		return

	}
}

func fff() {
	fmt.Println(333)
	time.Sleep(6 * time.Second)
}

/**
  通道方式处理并发的理论基础：csp
*/
func main() {

	//chDemoemo1()

	//channel作为返回值
	//chDemo2()

	//单向通道
	//chDemo3()

	//缓存通道:  通道关闭后仍然可以取到0值；用for range循环，通道未关闭会阻塞
	chDemo4()

	//等待任务执行完毕再退出程序，使用sync.WaitGroup
	chDemo5()

	//使用超时通道
	chDemo6()
}

type wworker struct {
	in chan int
	wg *sync.WaitGroup
}

func doWork(id int, ch chan int, wg *sync.WaitGroup) {
	for n := range ch {
		fmt.Printf("channel%d: %c\n", id, n)
		wg.Done()
	}
}
func createWorker5(id int, wg *sync.WaitGroup) chan int {

	//w := wworker{
	//	in: make(chan int),
	//	wg: wg,
	//}
	ch := make(chan int)
	go doWork(id, ch, wg)
	return ch

}

func chDemo5() {
	var wg sync.WaitGroup

	//var workers [10]wworker
	var chs [10]chan int
	for i := 0; i < 10; i++ {
		//workers[i] = createWorker5(i, &wg)
		chs[i] = createWorker5(i, &wg)
	}
	//wg.Add(1)
	for i, wk := range chs {
		wg.Add(1)
		wk <- 'a' + i

	}
	for i, wk := range chs {
		wg.Add(1)
		wk <- 'A' + i

	}

	wg.Wait()
}
